package com.fin.zw.aiqas.service;


import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.fin.zw.aiqas.entity.*;
import com.fin.zw.aiqas.enums.FormulaType;
import com.fin.zw.aiqas.enums.HitStatus;
import com.fin.zw.aiqas.enums.QualityStatus;
import com.fin.zw.aiqas.enums.Status;
import com.fin.zw.aiqas.model.component.Drill;
import com.fin.zw.aiqas.model.component.JsonDataModel;
import com.fin.zw.aiqas.repository.*;
import com.fin.zw.aiqas.util.AudioUtil;
import com.fin.zw.aiqas.util.BadRequestException;
//import com.fin.zw.aiqas.util.FileTransService;
import com.fin.zw.aiqas.util.SocketClientUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.thymeleaf.util.ListUtils;
import org.thymeleaf.util.SetUtils;

import java.util.*;
import java.util.stream.Collectors;

@Service("executeDetailFileService")
public class ExecuteDetailFileService {

    private final static Logger log = LoggerFactory.getLogger(ExecuteDetailFileService.class);

    @Autowired
    private InspectionDetailRepository inspectionDetailRepository;

    @Autowired
    private ConverseRepository converseRepository;

    @Autowired
    private CalculationResultService calculationResultService;

    @Autowired
    private ConverseRuleRepository converseRuleRepository;

    @Autowired
    private ScenesRepository scenesRepository;

    @Autowired
    private TemplateInfoService templateInfoService;

    @Autowired
    private TaskInfoRepository taskInfoRepository;

    @Autowired
    private FileTransService fileTransService;

//    @Autowired
//    private RestfulFileService restfulFileService;

    @Value("${root.drill}")
    private String drillUrl;

    @Value("${speech.recognition.service}")
    private String speechRecognitionServer;


    public InspectionDetail executeTaskInfo(InspectionDetail detail, Long taskId) {
        Optional<TaskInfo> optional = taskInfoRepository.findById(taskId);
        if (!optional.isPresent()) {
            throw new BadRequestException("", "推送的任务信息不存在！+");
        }
        TaskInfo taskInfo = optional.get();
        if (taskInfo.getStatus().equals(Status.START)) {
            String result = new String();
            String status = "success";
            try {
                if ("aliyun".equals(speechRecognitionServer)) {
                    String resultJson = fileTransService.speechRecognition(detail.getVoiceUrl());
                    result = fileTransService.formatResult(resultJson);
                } else if ("xunfei".equals(speechRecognitionServer)) {
                    result = AudioUtil.audioToText(detail.getVoiceUrl());
                } else if ("offaili".equals(speechRecognitionServer)) {
                    //result = restfulFileService.offRestfulFile(detail.getVoiceUrl());
                    log.info("未知的阿里离线语音识别");
                } else {
                    log.info("未知的语音识别服务标识,请联系管理员!!!");
                }
            } catch (Exception e) {
                status = "fail";
                log.error("文件路径：" + detail.getVoiceUrl() + "翻译出错了！");
            } finally {
                if (status.equals("success")) {
                    return executeDetail(detail, status, result);
                } else {
                    return executeFailDetail(detail, status);
                }
            }
        }
        return null;
    }


    /**
     * 文件翻译错误
     *
     * @param info
     */
    public InspectionDetail executeFailDetail(InspectionDetail info, String status) {
        info.setDetailStatus(status);
        info.setQualityStatus(QualityStatus.FINISH);
        info = inspectionDetailRepository.save(info);
        return info;
    }

    /**
     * 执行某个文件
     *
     * @param info
     * @param status
     */
    public InspectionDetail executeDetail(InspectionDetail info, String status, String jsonData) {
        info.setDetailStatus(status);
        log.info("修改质检明细状态：" + info.getId());
        Set<RuleInfo> ruleInfos = new HashSet<>();//获取文件中所有的规则
        //更改正在质检状态
        log.info("开始质检文本内容对应的命中规则");
        List<Converse> converses = convertToList(jsonData, info);
        //文件内容信息处理
        List<Converse> converseList = converseRepository.saveAll(converses);
        if (haveSentence(info.getTaskInfo())) { //规则都是句子
            info.setRunDate(new Date());
            info = inspectionDetailRepository.save(info);
            try {
                executeSentence(info, converses);
            } catch (Exception e) {
                log.error("文件：" + info.getVoiceUrl() + "句子质检出错了！");
            }
            return null;
        } else {  //针对关键词质检
            //针对每句话做质检并保存
            List<ConverseRule> converseRuleList = saveConverseRule(info, converseList, ruleInfos);
            if (!ListUtils.isEmpty(converseRuleList)) {
                converseRuleRepository.saveAll(converseRuleList);
            }
            if (ruleInfos != null && !ruleInfos.isEmpty()) {
                info.setHitStatus(HitStatus.HIT);
                List<String> ruleName = ruleInfos.stream().map(e -> e.getRuleName()).collect(Collectors.toList());
                info.setHitRule(String.join(",", ruleName));//命中规则名称
            }
            //质检结果明细信息处理
            info.setRunDate(new Date());
            info.setQualityStatus(QualityStatus.FINISH);
            info = inspectionDetailRepository.save(info);
            log.info("质检完成，并修改质检明细对应的状态");
            return info;
        }
    }


    /**
     * 获取文本内容并命中规则信息
     *
     * @param jsonData 调用文件解析后的json
     * @param info
     * @return
     */
    public List<Converse> convertToList(String jsonData, InspectionDetail info) {
        //质检并解析语音识别语句
        List<Converse> converseList = new ArrayList<>();

        List<JsonDataModel> converses = JSONObject.parseArray(jsonData, JsonDataModel.class);
        if (CollectionUtil.isEmpty(converses))
            return converseList;
        for (JsonDataModel model : converses) {
            Converse converse = new Converse();
            converse.setFileName("");
            converse.setFilePath("");
            converse.setTaskInfo(info.getTaskInfo());
            converse.setInspectionDetail(info);
            converse.setBg(Long.valueOf(model.getBg()));
            converse.setEd(Long.valueOf(model.getEd()));
            converse.setStartTime(new Date());
            converse.setEndTime(new Date());
            converse.setSortNum(converses.indexOf(model));
            converse.setContent(model.getOnebest());
            converse.setSpeaker(model.getSpeaker());
            converseList.add(converse);
        }
        return converseList;
    }

    /**
     * 根据任务查询此任务下是否有包含句子类型的质检点
     *
     * @param taskInfo 任务信息
     * @return
     */
    public boolean haveSentence(TaskInfo taskInfo) {
        Set<RuleInfo> ruleInfoSet = taskInfo.getRuleInfoSet();
        if (!SetUtils.isEmpty(ruleInfoSet)) {
            for (RuleInfo ruleInfo : ruleInfoSet) {
                Set<FormulaInfo> formulaInfos = ruleInfo.getFormulaInfos();
                if (!SetUtils.isEmpty(formulaInfos)) {
                    for (FormulaInfo formulaInfo : formulaInfos) {
                        if (formulaInfo.getFormulaType().equals(FormulaType.SENTENCE)) {
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }


    /**
     * 对句子进行预测发送请求
     *
     * @param info
     * @param converses
     * @throws Exception
     */
    public void executeSentence(InspectionDetail info, List<Converse> converses) throws Exception {
        log.info("开始组装句子类型质检数据......");
        ScenesInfo scenesInfo = scenesRepository.findById(info.getTaskInfo().getScenesInfoId()).orElseThrow(() -> new BadRequestException("", "该场景不存在"));
        List<List<Object>> list = templateInfoService.getDrillHead(scenesInfo.getId());
        if (list != null && !list.isEmpty()) {
            int index = list.get(0).size();
            for (Converse converse : converses) {
                List<Object> textList = new ArrayList<>();
                for (int i = 0; i < (index - 1); i++) {
                    textList.add(0);
                }
                textList.add(converse.getContent());
                list.add(textList);
            }
            Drill drill = new Drill();
            drill.setData(list);
            drill.setId(scenesInfo.getId().toString());
            drill.setCode(scenesInfo.getScenesCode());
            drill.setName(scenesInfo.getName());
            drill.setCommand("predict");
            drill.setStatus("ready");
            drill.setDetailId(info.getId().toString());
            String json = JSONObject.toJSONString(drill);
            log.info("场景样本预测数据:" + json);
            SocketClientUtils.sendText(drillUrl, json);
        }
    }

    public List<ConverseRule> saveConverseRule(InspectionDetail info, List<Converse> converseList, Set<RuleInfo> ruleInfos) {
        List<ConverseRule> resultList = new ArrayList<>();
        for (Converse converse : converseList) {
            List<ConverseRule> converseRuleList = new ArrayList<>();
            Set<RuleInfo> ruleInfoSet = calculationResultService.getCalculationRuleInfo(info.getTaskInfo().getId(), converse.getContent());
            if (!SetUtils.isEmpty(ruleInfoSet)) {
                ruleInfos.addAll(ruleInfoSet);//统计使用
                ruleInfoSet.forEach(ruleInfo -> {
                    ConverseRule converseRule = new ConverseRule();
                    log.info("converse的id是：" + converse.getId());
                    converseRule.setConverseId(converse.getId());
                    converseRule.setRuleInfo(ruleInfo);
                    resultList.add(converseRule);
                    converseRuleList.add(converseRule);
                });
            }
        }
        return resultList;
    }

}